package com.youlu.campus.service.wechat.impl;

import com.alibaba.fastjson.JSON;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.entity.WechatConfigInfo;
import com.youlu.campus.entity.domain.WechatAccessToken;
import com.youlu.campus.entity.domain.WechatSiteUserInfoDomain;
import com.youlu.campus.service.wechat.WechatConfigInfoService;
import com.youlu.campus.service.wechat.WechatService;
import lombok.extern.slf4j.Slf4j;
import net.polyv.live.util.HttpClientUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WechatServiceImpl implements WechatService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private WechatConfigInfoService wechatConfigInfoService;

    private String wechatAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
    /**
     * 获取用户信息URL
     */
    private String getUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
    /**
     * 用户accessToken
     */
    public static String wechatUserAccessToken = "com.luyou.wechat.accessToken.appId:%s.openId:%s";

    @Override
    public WechatAccessToken getAccessToken(String appId, String code) {
        log.info(":>>> 开始获取AccessToken:{},code:{}", appId, code);
        WechatConfigInfo config = wechatConfigInfoService.find(appId);
        if (Objects.isNull(config)) {
            log.error(":>>> 微信应用:{} 配置不存在", appId);
            throw new BusinessException("微信应用配置不存在");
        }
        WechatAccessToken accessToken = this.getAccessTokenFromWechat(appId, config.getAppSecret(), code);
        if (StringUtils.isNotBlank(accessToken.getOpenId()) && StringUtils.isNotBlank(accessToken.getAccessToken())) {
            String key = this.getUserAccessTokenPreKey(appId, accessToken.getOpenId());
            redisTemplate.opsForValue().set(key, JSON.toJSONString(accessToken), 7000, TimeUnit.SECONDS);
            log.info(":>>> 设置应用:{},用户:{} accessToken 缓存:{}", appId, accessToken.getOpenId(), JSON.toJSONString(accessToken));
        }

        return accessToken;
    }

    @Override
    public WechatSiteUserInfoDomain getUserInfo(String appId, String openId) {
        log.info(":>>> 开始获取用户信息appId:{},openId:{}", appId, openId);
        WechatAccessToken accessToken = this.getAccessTokenByOpenId(appId, openId);
        String userInfoStr = HttpClientUtil.getInstance().sendHttpGet(String.format(getUserInfoUrl, appId, accessToken.getAccessToken(), openId));
        log.info(":>>> 获取openId:{}的用户信息:{}", openId, userInfoStr);
        if (StringUtils.isBlank(userInfoStr)) {
            log.error(":>>> 获取用户信息失败 with openId:{}", openId);
            return null;
        }
        WechatSiteUserInfoDomain wechatSiteUserInfo = JSON.parseObject(userInfoStr, WechatSiteUserInfoDomain.class);
        return wechatSiteUserInfo;
    }

    @Override
    public WechatAccessToken getAccessTokenByOpenId(String appId, String openId) {
        log.info(":>>> 开始从微信获取AccessToken:appId:{},openId:{}", appId, openId);
        if (StringUtils.isBlank(appId) || StringUtils.isBlank(openId)) {
            log.error(":>>> 获取应用:{} AccessToken参数错误", appId);
        }
        WechatAccessToken token = null;
        final String key = getUserAccessTokenPreKey(appId, openId);
        Object v = redisTemplate.opsForValue().get(key);
        if (Objects.isNull(v)) {
            log.info(":>>> 应用:{},openId:{} AccessToken 缓存中不存在", appId, openId);
            throw new BusinessException("AccessToken 不存在");
        }
        token = JSON.parseObject(v.toString(), WechatAccessToken.class);
        if (Objects.isNull(token)) {
            throw new BusinessException("AccessToken 不存在");
        }
        return token;
    }


    protected WechatAccessToken getAccessTokenFromWechat(String appId, String appSecret, String code) {
        String accessTokenStr = HttpClientUtil.getInstance().sendHttpGet(String.format(wechatAccessTokenUrl, appId, appSecret, code));
        log.info(":>>> 获取AccessToken:{}", accessTokenStr);
        if (StringUtils.isBlank(accessTokenStr)) {
            log.error(":>>> 获取AccessToken失败");
            return null;
        }
        WechatAccessToken wechatAccessToken = JSON.parseObject(accessTokenStr, WechatAccessToken.class);
        if (Objects.isNull(wechatAccessToken)) {
            throw new BusinessException("获取AccessToken失败");
        }
        return wechatAccessToken;
    }

    /**
     * 获取用户AccessToken缓存前缀
     *
     * @param appId
     * @param openId
     * @return
     */
    private String getUserAccessTokenPreKey(String appId, String openId) {
        String key = String.format(wechatUserAccessToken, appId, openId);
        return key;
    }
}
